package com.apes.fn.server.productRequire;

import com.apes.fn.scm.crossCompany.transfer.model.CrossCompanyTransferNew;
import com.apes.fn.tms.model.Waybill;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEvent;
import com.apes.framework.plugin.outbox.OutboxEventRepository;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrderItem;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.Transfer;
import lombok.Data;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

@Service("requireInfoCOnfigurConvertService")
public class RequireInfoCOnfigurConvertService extends DomainService {


    private static Map<String, Function<Object, List<Map>>> getFunction = initAllDataConvert();

    @Autowired
    private RequireInfoConfigurRepository requireInfoConfigurRepository;

    public void sourceDataConvert(SimpleRequest request) {
        content content = new content(request.getData(), this);
        Map<String, Function<Object, List<Map>>> map = getFunction;
        List requireInfoConfigurs= requireInfoConfigurRepository.findAll(" SELECT DISTINCT BUSINESS_TYPE_ID FROM STOCK_REQUIRE_INFO_CONFIGUR ");
        requireInfoConfigurs.stream().anyMatch(requireInfoConfigur -> {
            Function f = map.get(requireInfoConfigur);
            List<Map> returnResult = (List<Map>) f.apply(content);
            if (returnResult.size() > 0) invoke("stock.requireLogistics.sourceRequire.create", returnResult);
            if (returnResult.size() > 0) return true;
            return false;
        });
    }


     @Data
     static class content {
        private RequireInfoCOnfigurConvertService requireInfoCOnfigurConvertService;
        private Object object;
        public content(Object obj, RequireInfoCOnfigurConvertService requireInfoCOnfigurConvertService) {
            this.object = obj;
            this.requireInfoCOnfigurConvertService = requireInfoCOnfigurConvertService;
        }

    }
    private static Map<String, Function<Object, List<Map>>> initAllDataConvert() {
        Map<String, Function<Object, List<Map>>> routings = new HashedMap();
        RequireInfoCOnfigurConvertService.requireDataConvert(routings);
        RequireInfoCOnfigurConvertService.purchaseOrderDataConvert(routings);

        RequireInfoCOnfigurConvertService.transferDataConvert(routings);
        RequireInfoCOnfigurConvertService.crossCompanyDataConvert(routings);
        RequireInfoCOnfigurConvertService.pickDataConvert(routings);
        RequireInfoCOnfigurConvertService.waybillDataConvert(routings);
        return routings;
    }

    /* 要货数据转换 */
    private static void requireDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("ProductRequire", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof ProductRequire)) return items;
            ProductRequire require = (ProductRequire) ((content) content).getObject();
            List<ProductRequireItem> requireItems = require.getProductRequireItems();
            if (requireItems == null || requireItems.size() == 0) return new ArrayList();

            requireItems.forEach(requireItem -> {
                ProductRequireItem singleRequireItem = requireItem;
                double qtyRequire = singleRequireItem.getQtyRequire();
                double qtyEnd = singleRequireItem.getQtyEnd();
                String states = qtyEnd > 0?"repeal":require.getState();
                PartyRole operator = SpringManager.getBean(PartyRoleRepository.class).findOne(require.getCreator() == null?"system":require.getCreator());
                double qty = "repeal".equals(states)? qtyEnd:qtyRequire;
                if (!("repeal".equals(states) && qty == 0))  {
                    String operatorName = "approve".equals(states)?require.getApproveId().getName():"repeal".equals(states)?require.getRepealId().getName():operator.getName();
                    items.add(MapUtil.mapper("productId", singleRequireItem.getProduct().getId(), "uomId", singleRequireItem.getUom().getId(), "uomName", singleRequireItem.getUom().getName(),
                            "sourceQty", qtyRequire, "qty", qty,
                            "id", require.getId(), "origin", require.getId(), "state", states, "innerBusinessType", require.getInnerBusinessType(), "operatorName", operatorName));
                }

            });
            return items;
        });
    }


    /**
     * 批量采购
     * 外采询价采购
     * @return
     */
    private static Map<String, Function<Object, List<Map>>> purchaseOrderDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("PurchaseOrder", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof PurchaseOrder)) return items;
            PurchaseOrder order = (PurchaseOrder) ((content) content).getObject();
            if ("CD0".equals(order.getSourceType())) return new ArrayList<>();
            String productRequire = order.getProductRequire();
            List<ProductRequireExpand> requireExpands = new ArrayList<>();
            boolean existsRequireExpand = ((content) content).requireInfoCOnfigurConvertService.qryRequireExpand(requireExpands, productRequire, order.getId());
            if (!existsRequireExpand) return new ArrayList<>();

            order.getPurchaseItems().forEach(singleOrderItem -> {
                PurchaseOrderItem item = singleOrderItem;
                double stopQty = item.getStopQty();
                double productUomQty = item.getProductUomQty();
                String productId = item.getProduct().getId();
                String states = stopQty > 0?"cancel":order.getState();
                double qty = "cancel".equals(states)? stopQty:productUomQty;
                PartyRole operator = SpringManager.getBean(PartyRoleRepository.class).findOne(order.getCreator() == null?"system":order.getCreator());
                String operatorName = "confirmed".equals(states)?order.getApproveUid().getName()
                        :"cancel".equals(states)?order.getCancelNameId().getName():"delete".equals(states)?order.getDeletePersonId().getName():operator.getName();
                Set originIds = new HashSet();
                List<Map> origins = ((content) content).requireInfoCOnfigurConvertService.getRequireExpandOrigin(requireExpands, productId, productRequire, originIds);
                origins.forEach(singleOrigin -> {
                    String origin = order.getSupplier().getParty().getName().indexOf("巴图鲁") != -1?order.getProductRequire():singleOrigin.get("origin").toString();

                    // 如果要货单物流跟踪没有消费完，需要要货物流先跟踪完
                    List<OutboxEvent> outboxevents  = getBean(OutboxEventRepository.class).findAll(JpaDsl.toCriteriaByEq("aggregateId", origin, "subscriber", "000383"));
                    if (!outboxevents.isEmpty()) {
                        throw new RuntimeException("要货单审核物流还未生成，请稍后~ ");
                    }

                    String upBusinessType = ((content) content).getRequireInfoCOnfigurConvertService().getUpBusinessType(origin);
                    items.add(MapUtil.mapper("productId", item.getProduct().getId(), "uomId", item.getUom().getId(), "uomName", item.getUom().getName(), "sourceQty", productUomQty, "qty", qty,
                            "id", order.getId(), "origin", singleOrigin.get("origin"), "state", states, "innerBusinessType", order.getInnerBusinessType(), "operatorName", operatorName, "upBusinessTypeId", upBusinessType,
                            "source", order.getId(), "itemIsOneMark", originIds.size() > 0?"real":"", "time", item.getExpectedArrivalTime() + "小时"));
                });
            });
            return items;
        });
        return routings;
    }

    // 采购获取针对特定数据消息的单据类型
    private String getUpBusinessType(String origin) {
        String upBusinessType = "";
        List inquiryOrders = SpringManager.getBean(ProductRequireRepository.class).findAll("SELECT COMMODITY_INQUIRY_ORDER_ID FROM STOCK_PRODUCT_REQUIRE_ITEM WHERE PRODUCT_REQUIRE_ID = '" + origin + "'");
        if (inquiryOrders.size() != 0) {
            String inquiryOrderId = String.valueOf(inquiryOrders.get(0));
            if (StringUtils.hasText(inquiryOrderId) && inquiryOrderId.indexOf("WC") != -1) upBusinessType = "ExternalInquiry";
            if (StringUtils.hasText(inquiryOrderId) && inquiryOrderId.indexOf("BI") != -1) upBusinessType = "BaturuInquiry";
        }
        return upBusinessType;
    }

    // 单个要货转储、批量转储
    private static void transferDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("Transfer", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof Transfer)) return items;
            Transfer transfer = (Transfer) ((content) content).getObject();
            List<ProductRequireExpand> requireExpands = new ArrayList<>();
            boolean existsRequireExpand = ((content) content).requireInfoCOnfigurConvertService.qryRequireExpand(requireExpands, transfer.getSource(), transfer.getId());
            if (!existsRequireExpand) return new ArrayList<>();
            transfer.getTransferItems().forEach(transferItem -> {
                String state = transfer.getState();
                double finishSum = transferItem.getFinishSum();
                double transferQty = transferItem.getTransferQty();
                if ("done".equals(state) && finishSum == 0) state = "empty"; // 全部收货为完成
                double qty = "done".equals(state) && finishSum > 0?finishSum:transferQty;
                PartyRole operator = SpringManager.getBean(PartyRoleRepository.class).findOne(transfer.getCreator() == null?"system":transfer.getCreator());
                String operatorName = "approve".equals(state) || ("approve".equals(state) && finishSum == 0)?transfer.getApproveUid().getName():"done".equals(state) && finishSum > 0?transfer.getStopUid().getName():operator.getName();
                String copyState = state;
                Set originIds = new HashSet();
                List<Map> origins = ((content) content).requireInfoCOnfigurConvertService.getRequireExpandOrigin(requireExpands, transferItem.getProduct().getId(), transfer.getSource(), originIds);
                origins.forEach(singleOrigin -> {

                    // 如果要货单物流跟踪没有消费完，需要要货物流先跟踪完
                    List<OutboxEvent> outboxevents = getBean(OutboxEventRepository.class).findAll(JpaDsl.toCriteriaByEq("aggregateId", singleOrigin.get("origin").toString(), "subscriber", "000383"));
                    if (!outboxevents.isEmpty()) {
                        throw new RuntimeException("要货单审核物流还未生成，请稍后~ ");
                    }

                    double newQty = Double.valueOf(singleOrigin.get("assignQty").toString());
                    newQty = newQty > 0?newQty:qty;
                    items.add(MapUtil.mapper("productId", transferItem.getProduct().getId(), "uomId", transferItem.getUom().getId(), "uomName", transferItem.getUom().getName(), "sourceQty", transferQty, "qty", newQty,
                            "itemIsOneMark", originIds.size() > 0?"real":"",
                            "id", transfer.getId(), "origin", singleOrigin.get("origin"), "state", copyState, "innerBusinessType", transfer.getInnerBusinessType(), "operatorName", operatorName, "source", transfer.getId(), "originLocationName", transfer.getOriginLocation().getName()));
                });
            });
            return items;
        });
    }

    /* 批量转储，获取要货扩展表中的要货单号 */
     private boolean qryRequireExpand(List<ProductRequireExpand> requireExpands, String requireId, String currentId) {
         requireExpands.addAll(SpringManager.getBean(ProductRequireExpandRepository.class).qryRequireExpand(currentId));
         if (requireExpands.isEmpty()) {
             if (StringUtils.hasText(requireId)) {
                 requireExpands.addAll(SpringManager.getBean(ProductRequireExpandRepository.class).findAll(JpaDsl.toCriteriaByEq("origin", requireId)));
                 if (requireExpands.isEmpty()) {
                     return false;
                 }
             } else {
                 return false;
             }
         }
         return true;
     }

     /* 获取要货单号 */
     private List<Map> getRequireExpandOrigin(List<ProductRequireExpand> requireExpands, String productId, String sourceOrigin, Set originIds) {
         List origins = new ArrayList();
         if (requireExpands.size() > 0) {
             requireExpands.stream().forEach(requireExpand -> {
                 if (requireExpand.getProductId().getId().equals(productId)) {
                     Map item = new HashedMap();
                     item.put("origin", requireExpand.getOrigin());
                     item.put("assignQty", requireExpand.getAssignQty());
                     item.put("distributionId", requireExpand.getDistributionId());
                     origins.add(item);
                 }
                 originIds.add(requireExpand.getOrigin());
             });
         } else { // 要货单还没有分配，没有配货单号
             Map item = new HashedMap();
             item.put("origin", sourceOrigin);
             item.put("assignQty", 0);
             origins.add(item);
             originIds.add(sourceOrigin);
         }

         return origins;
     }



    /* 新跨公司调拨 */
    private static void crossCompanyDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("CrossCompanyTransferNew", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof CrossCompanyTransferNew)) return items;
            CrossCompanyTransferNew crossCompanyNew = (CrossCompanyTransferNew) ((content) content).getObject();

            List<ProductRequireExpand> requireExpands = new ArrayList<>();
            boolean existsRequireExpand = ((content) content).requireInfoCOnfigurConvertService.qryRequireExpand(requireExpands, crossCompanyNew.getSource(), crossCompanyNew.getId());
            if (!existsRequireExpand) return new ArrayList<>();
            crossCompanyNew.getCrossCompanyTransferItems().forEach(crossCompanyItem -> {
                String state = crossCompanyNew.getState();
                double finishSum = crossCompanyItem.getFinishSum();
                double productSum = crossCompanyItem.getProductSum();
                double shipNum = crossCompanyItem.getShipNum();
                if (finishSum > 0) state = "done";
                if (("done".equals(state) && finishSum == 0) || shipNum > 0) state = "empty";
                double qty = "done".equals(state) && finishSum > 0?productSum:finishSum;
                PartyRole operator = SpringManager.getBean(PartyRoleRepository.class).findOne(crossCompanyNew.getCreator() == null?"system":crossCompanyNew.getCreator());
                String operatorName = "approve".equals(state) && finishSum == 0?crossCompanyNew.getApproveUid().getName():("done".equals(state) || "approve".equals(state)) && finishSum > 0?crossCompanyNew.getStopUid().getName():operator.getName();
                Set originIds = new HashSet();
                List<Map> origins = ((content) content).requireInfoCOnfigurConvertService.getRequireExpandOrigin(requireExpands, crossCompanyItem.getProduct().getId(), crossCompanyNew.getSource(), originIds);
                String copyState = state;
                origins.forEach(singleOrigin -> {

                    // 如果要货单物流跟踪没有消费完，需要要货物流先跟踪完
                    List<OutboxEvent> outboxevents  = getBean(OutboxEventRepository.class).findAll(JpaDsl.toCriteriaByEq("aggregateId", singleOrigin.get("origin").toString(), "subscriber", "000383"));
                    if (!outboxevents.isEmpty()) {
                        throw new RuntimeException("要货单审核物流还未生成，请稍后~ ");
                    }

                    double newQty = Double.valueOf(singleOrigin.get("assignQty").toString());
                    newQty = newQty > 0?newQty:qty;
                    items.add(MapUtil.mapper("productId", crossCompanyItem.getProduct().getId(), "uomId", crossCompanyItem.getUom().getId(), "uomName", crossCompanyItem.getUom().getName(), "sourceQty", productSum, "qty", newQty,
                            "id", crossCompanyNew.getId(), "origin", singleOrigin.get("origin"), "state", copyState, "innerBusinessType", crossCompanyNew.getInnerBusinessType(), "operatorName", operatorName, "upBusinessTypeId", "",
                            "originLocationName", crossCompanyNew.getShipLocation().getName(), "source", crossCompanyNew.getId(), "itemIsOneMark", originIds.size() > 0?"real":""));
                });
            });
            return items;
        });
    }

    // 运单
    private static void waybillDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("Waybill", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof Waybill)) return items;
            Waybill waybill = (Waybill) ((content) content).getObject();
            PurchaseOrder purchaseOrder = SpringManager.getBean(PurchaseOrderRepository.class).waybillPurchaseOrder(waybill.getSourceBusinessKey());
            List<ProductRequireExpand> requireExpands = new ArrayList<>();
            boolean existsRequireExpand = ((content) content).requireInfoCOnfigurConvertService.qryRequireExpand(requireExpands,  StringUtils.isEmpty(purchaseOrder.getProductRequire())?"":purchaseOrder.getProductRequire(), purchaseOrder.getId());
            if (!existsRequireExpand) return new ArrayList<>();
            waybill.getWaybillCargoDetailsSet().forEach(cargoDetails -> {
                Set originIds = new HashSet();
                List<Map> origins = ((content) content).requireInfoCOnfigurConvertService.getRequireExpandOrigin(requireExpands, cargoDetails.getProductId().getId(), purchaseOrder.getProductRequire(), originIds);
                origins.forEach(singleOrigin -> {
                    Map requireExpand = (Map) singleOrigin;
                    items.add(MapUtil.mapper("productId", cargoDetails.getProductId().getId(), "uomId", cargoDetails.getProductUomId().getId(), "uomName", cargoDetails.getProductUomId().getName(),
                            "sourceQty", cargoDetails.getNumberQty(), "qty", cargoDetails.getNumberQty(), "id", waybill.getId(), "origin", requireExpand.get("origin"), "state", waybill.getTransportStatus(), "innerBusinessType", waybill.getInnerBusinessType(), "operatorName", "",
                            "upBusinessTypeId", "", "originLocationName", purchaseOrder.getLocation().getName(), "source", waybill.getId()));
                });
            });
            return items;
        });
    }


    // 交货单 ---关注各个字段值
    private static void pickDataConvert(Map<String, Function<Object, List<Map>>> routings) {
        routings.put("Pick", content -> {
            List items = new ArrayList<>();
            if (!(((content) content).getObject() instanceof Pick)) return items;
            Pick pick = (Pick) ((content) content).getObject();
            AtomicReference puraseOrderRequireId = new AtomicReference("");
            if (pick.getOriginBusinessType().equals("PurchaseOrder")) { // 临时处理，外采要货采购订单应该生成要货扩展表
                puraseOrderRequireId.set(SpringManager.getBean(PurchaseOrderRepository.class).findOne(pick.getOrigin()).getProductRequire());
            }
            String state = pick.getState();
            List<ProductRequireExpand> requireExpands = new ArrayList<>();
            boolean existsRequireExpand = ((content) content).requireInfoCOnfigurConvertService.qryRequireExpand(requireExpands, puraseOrderRequireId.get() == null?"":puraseOrderRequireId.get().toString(), pick.getOrigin());
            if (!existsRequireExpand) return new ArrayList<>();

            pick.getPickItems().forEach(pickItem -> {
                double orderedQty = pickItem.getOrderedQty();
                double qtyDone = pickItem.getQtyDone();
                double qty = "done".equals(state)?qtyDone:orderedQty;
                PartyRole operator = SpringManager.getBean(PartyRoleRepository.class).findOne(pick.getCreator() == null?"system":pick.getCreator());
                String operatorName = "done".equals(state) || "cancel".equals(state)?pick.getDoneUid().getName():operator.getName();
                Set originIds = new HashSet();
                List<Map> origins = ((content) content).requireInfoCOnfigurConvertService.getRequireExpandOrigin(requireExpands, pickItem.getProduct().getId(), puraseOrderRequireId.get().toString(), originIds);
                origins.forEach(singleOrigin -> {

                    // 如果要货单物流跟踪没有消费完，需要要货物流先跟踪完
                    List<OutboxEvent> outboxevents = getBean(OutboxEventRepository.class)
                            .findAll(JpaDsl.toCriteria("aggregateId", "eq", singleOrigin.get("distributionId").toString(), "subscriber", "in", Arrays.asList("000384", "000385", "000386")));
                    if (!outboxevents.isEmpty()) {
                        throw new RuntimeException("要货单审核物流还未生成，请稍后~ ");
                    }

                    double newQty = Double.valueOf(singleOrigin.get("assignQty").toString());
                    newQty = newQty > 0?newQty:qty;
                    items.add(MapUtil.mapper("productId", pickItem.getProduct().getId(), "uomId", pickItem.getUom().getId(), "uomName", pickItem.getUom().getName(), "sourceQty", orderedQty, "qty", newQty,
                            "id", pick.getId(), "origin", singleOrigin.get("origin"), "state", state, "innerBusinessType", pick.getInnerBusinessType(), "operatorName", operatorName, "source", pick.getId(),
                            "originLocationName", pick.getLocation().getName(), "upBusinessTypeId", pick.getOperation().equals("receipt")?"":pick.getOriginBusinessType(),
                            "itemIsOneMark", origins.size() > 0?"real":""));
                });
            });
            return items;
        });
    }
}
